package com.mrdeer.iot.handler;

import com.mrdeer.iot.bean.command.Protocol;
import com.mrdeer.iot.constant.FrameConst;
import com.mrdeer.iot.utils.HexHelper;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;

import java.util.List;

/**
 * 自定义协议解析
 */
@Slf4j
public class ProtocolDecoderHandler extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        log.info("启动解码器====>目前数据缓存大小{}", in.readableBytes());

        //刻度长度必须大于基本最小长度
        if (in.readableBytes() >= FrameConst.acceptMinMsgLength) {
            //防止socket字节流攻击、客户端传来的数据过大，这里需要对数据进行过滤掉
            if (in.readableBytes() >= FrameConst.acceptMaxMsgLength) {
                in.skipBytes(in.readableBytes());
                return;
            }
            //记录包头开始位置
            int beginReader = 0;
            while (true) {
                beginReader = in.readerIndex();   //记录包头开始位置
                in.markReaderIndex();       //标记包头开始index
                //读取协议开始标志
                if (in.readByte() == FrameConst.header) {
                    break;  //如果是开始标记，那么就结束查找
                }
                //如果找不到包头，这里要一个一个字节跳过
                in.resetReaderIndex();
                in.readByte();

                //当跳过后，如果数据包不符合长度的，结束本次协议解析
                if (in.readableBytes() < FrameConst.acceptMinMsgLength) {
                    return;
                }
            }
            byte code = in.readByte();      //读取厂商代码
            byte version = in.readByte();   //读取协议版本
            byte length = in.readByte();    //读取协议有效长度
            byte[] dest = new byte[6];      //分配地址 6 bytes
            dest[0] = in.readByte();
            dest[1] = in.readByte();
            dest[2] = in.readByte();
            dest[3] = in.readByte();
            dest[4] = in.readByte();
            dest[5] = in.readByte();

            byte type = in.readByte();      //读取帧类型
            if (!ArrayUtils.contains(FrameConst.req_types, HexHelper.numToHex8(type))) {
                log.info("类型不正确");
                return;
            }

            byte[] data = new byte[length - 7];     //分配数据信息 length-7
            for (int i = 0; i < length - 7; i++) {
                data[i] = in.readByte();
            }

            byte[] crc = new byte[2];
            crc[0] = in.readByte();
            crc[1] = in.readByte();

            Protocol protocol = new Protocol();

            protocol.setHeader(HexHelper.numToHex8(FrameConst.header));
            protocol.setCode(HexHelper.numToHex8(code));
            protocol.setVersion(HexHelper.numToHex8(version));
            protocol.setLength(HexHelper.numToHex8(length));
            protocol.setDest(HexHelper.convertBytesToHexString(dest));
            protocol.setType(HexHelper.numToHex8(type));
            protocol.setData(HexHelper.convertBytesToHexString(data));
            protocol.setCrc(HexHelper.convertBytesToHexString(crc));

            log.info("Protocol:" + protocol.toString());

            out.add(protocol);
        }
    }
}
